iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 4
1

這裡遇到的一個問題是,當fab點下,跳出自訂的layout(dialog_add)後
回到MainActivity畫面,再次點擊fab,就會閃退,報錯

/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.tobuylist, PID: 12402
    java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

請教恩師後,發現原本dialogBuilder沒有呼叫setOnDismissListener這個方法,要加上去

.setOnDismissListener {
                    (dialogItem.parent as ViewGroup).removeView(dialogItem)
                }

得到的解釋是一個容器同時只能裝一個view,第一次點擊fab,
讓dialogBuilder這個容器.setView(dialogItem)裝了這個view之後,沒有remove的動作,
所以當再次點fab,又要再setView時,裡面已經有先前的那個view,就會出錯,
因此setOnDismissListener裡面呼叫removeView()就是用來當dialog結束後,將內容的view給remove掉

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val dialogBuilder = AlertDialog.Builder(this@MainActivity)
        val dialogItem = LayoutInflater.from(this).inflate(R.layout.dialog_add, null)
//        在自訂的dialog中,若要調用view,須寫findViewById
        val dialogDate = dialogItem.findViewById<TextView>(R.id.tv_dialog_date)
        val date_button = dialogItem.findViewById<Button>(R.id.btn_date)

//      清單顯示部分
        pieceList.add(item)
        recycler_view.adapter = RecyclerViewAdapter(pieceList)
        recycler_view.layoutManager = LinearLayoutManager(this)
//      float action button
        fab.setOnClickListener {
            dialogDate.text = SimpleDateFormat("yyyy/MM/dd").format(System.currentTimeMillis())
            dialogBuilder
                .setTitle("新增清單")
                .setView(dialogItem)
//      設定當dialog被點掉時,remove原來放進來的view(dialogItem),否則再次點fab時會丟exception
                .setOnDismissListener {
                    (dialogItem.parent as ViewGroup).removeView(dialogItem)
                }
                .show()
            date_button.setOnClickListener {
                val c = Calendar.getInstance()
                val year = c.get(Calendar.YEAR)
                val month = c.get(Calendar.MONTH)
                val day = c.get(Calendar.DAY_OF_MONTH)
                DatePickerDialog(this, { _, year, month, day ->
                    run {
//                        val format = "你設定的日期為:${setDateFormat(year, month, day)}"
//                        val formatDate = SimpleDateFormat("yyyy/MM/dd").parse("$year/$month/$day")
                        dialogDate.text = "$year/${month+1}/$day"
                    }
                }, year, month, day).show()
            }
        }
    }
}

上面的方式,再次點fab,再次裝的view,是原先的view,因此若原先的view有編輯,
相關的資訊會被記錄下來,再次點fab,再次裝的view,就會是前次有輸入過的內容
例如:

如果是不想要這樣的情形,就要改為每次點fab時,都新建一個dialogItem再丟給setView
因此每次點fab,都會跳一個新的dialog,也不會報錯
只是此方法相對耗能,因為每次都要inflate一個新的view,不過在簡單的範例上感覺不到影響
修改方式為將以下4個變數放在fab.setOnClickListener中宣告

val dialogBuilder = AlertDialog.Builder(this@MainActivity)
val dialogItem = LayoutInflater.from(this).inflate(R.layout.dialog_add, null)
val dialogDate = dialogItem.findViewById<TextView>(R.id.tv_dialog_date)
val date_button = dialogItem.findViewById<Button>(R.id.btn_date)
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val dialogBuilder = AlertDialog.Builder(this@MainActivity)
//      清單顯示部分
        pieceList.add(item)
        recycler_view.adapter = RecyclerViewAdapter(pieceList)
        recycler_view.layoutManager = LinearLayoutManager(this)
//      float action button
        fab.setOnClickListener {
            val dialogItem = LayoutInflater.from(this).inflate(R.layout.dialog_add, null)
            //        在自訂的dialog中,若要調用view,須寫findViewById
            val dialogDate = dialogItem.findViewById<TextView>(R.id.tv_dialog_date)
            val date_button = dialogItem.findViewById<Button>(R.id.btn_date)
            dialogDate.text = SimpleDateFormat("yyyy/MM/dd").format(System.currentTimeMillis())
            dialogBuilder
                .setTitle("新增清單")
                .setView(dialogItem)
                .show()
            date_button.setOnClickListener {
                val c = Calendar.getInstance()
                val year = c.get(Calendar.YEAR)
                val month = c.get(Calendar.MONTH)
                val day = c.get(Calendar.DAY_OF_MONTH)
                DatePickerDialog(this, { _, year, month, day ->
                    run {
//                        val format = "你設定的日期為:${setDateFormat(year, month, day)}"
//                        val formatDate = SimpleDateFormat("yyyy/MM/dd").parse("$year/$month/$day")
                        dialogDate.text = "$year/${month+1}/$day"
                    }
                }, year, month, day).show()
            }
        }
    }
}


上一篇
Day 3--AlertDialog(一)
下一篇
Day 5--Room(一) 簡介
系列文
程式初學:Android與Kotlin30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言